package com.example;

import org.hibernate.*;
import org.hibernate.cfg.Configuration;

import javax.persistence.criteria.CommonAbstractCriteria;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

public class Main {
    public static void main(String[] argv) throws Exception{
        // get orm ready
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();

        long startTime = System.currentTimeMillis();
        Set<String> names1 = ORM_way(sessionFactory);
        //Set<String> names1 = ORM_fixed(sessionFactory);
        long t1 = System.currentTimeMillis() - startTime;

        startTime = System.currentTimeMillis();
        Set<String> names2 = SQL_way(sessionFactory);
        long t2 = System.currentTimeMillis() - startTime;

        assert(names1.size() == names2.size());

        // result
        System.out.printf("ORM way: %d ms\n", t1);
        System.out.printf("SQL way: %d ms\n", t2);

        sessionFactory.close();
    }

    public static Set<String> ORM_way(SessionFactory sessionFactory) {
        Set<String> result = new HashSet<>();

        try(Session session = sessionFactory.openSession()) {
            CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
            CriteriaQuery<Company> criteria = criteriaBuilder.createQuery(Company.class);
            criteria.from(Company.class);
            List<Company> list = session.createQuery(criteria).getResultList();

            for (Company company : list) {
                for (Employee employee : company.getEmployeeSet()) {
                    result.add(employee.getName());
                }
            }

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    public static Set<String> SQL_way(SessionFactory sessionFactory) throws Exception{
        Set<String> result = new HashSet<>();

        Driver driver = new org.postgresql.Driver();

        Properties properties = new Properties();
        properties.setProperty("user", "postgres");
        properties.setProperty("password", "nopass");

        Connection connection = driver.connect("jdbc:postgresql://localhost:5432/test", properties);

        PreparedStatement statement = connection.prepareStatement("select t_company.name, t_employee.name from t_company join t_employee on t_company.id = t_employee.company_id");
        ResultSet resultSet = statement.executeQuery();

        while (resultSet.next()) {
            result.add(resultSet.getString(2));
        }

        return result;
    }

    public static Set<String> ORM_fixed(SessionFactory sessionFactory) throws Exception {
        Set<String> result = new HashSet<>();

        try(Session session = sessionFactory.openSession()) {
            Criteria criteria = session.createCriteria(Company.class);
            criteria.setFetchMode("contact", FetchMode.EAGER);
            List<Company> list = criteria.list();

            for (Company company : list) {
                for (Employee e : company.getEmployeeSet()) {
                    result.add(e.getName());
                }
            }
        }

        return result;
    }
}
